package com.example.lvsuo.config;

import com.auth0.jwt.interfaces.Claim;
import com.example.lvsuo.modal.Constant;
import com.example.lvsuo.modal.MyUserDetailService;
import com.example.lvsuo.modal.Result;
import com.example.lvsuo.utils.JwtUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;

@EnableWebSecurity
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    MyUserDetailService mds;
//    System_userServiceImpl ssi;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//        super.configure(auth);
        auth.userDetailsService(mds).passwordEncoder(new BCryptPasswordEncoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
//        super.configure(http);
        http.authorizeRequests().antMatchers("/systemUser/add").permitAll()
                .antMatchers("/systemAuthority/delete").permitAll()
                .antMatchers("/systemUser/add" ,"/alipaytest","/createCommonQRCode","/fukuanchenggong").permitAll();
        //自定义过滤器    在UsernamePasswordAuthenticationFilter之前执行
        http.addFilterBefore((req,resp,auth)->{
            HttpServletRequest re=(HttpServletRequest)req;
            String token=re.getHeader("token");
            try {
                if(!ObjectUtils.isEmpty(token)){
                    //如果不抛出异常，就表示校验通过
                    Map<String, Claim> check = JwtUtils.check(token);
                    String user=check.get("user").asString();
                    String role=check.get("role").asString();
                    List<GrantedAuthority> grantedAuthorities = AuthorityUtils.commaSeparatedStringToAuthorityList(role);
                    //封装auth
                    UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(user, null, grantedAuthorities);
                    //存入securitycontextholder
                    SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
                }
            }catch (Exception e){
                e.printStackTrace();
                if (e.getMessage().contains("The Token has expired on")){
                    Result ok = Result.back(Constant.Token.getValue(), "身份已过期，请重新登录！", e.getMessage());
                    resp.setContentType("application/json;charset=utf-8");
                    ObjectMapper mapper=new ObjectMapper();
                    mapper.writeValue(resp.getWriter(),ok);
                }else{
                    Result ok = Result.back(Constant.ERROR.getValue(), "出错啦！", e.getMessage());
                    resp.setContentType("application/json;charset=utf-8");
                    ObjectMapper mapper=new ObjectMapper();
                    mapper.writeValue(resp.getWriter(),ok);
                }
            }
            auth.doFilter(req,resp);
        }, UsernamePasswordAuthenticationFilter.class);

        //关闭默认的session机制
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

        http.csrf().disable();
        //请求没有权限时的异常处理
        http.exceptionHandling().authenticationEntryPoint((req,resp,auth)->{
            Result ok = Result.back(Constant.ERROR.getValue(), "请先登录！", "");
            resp.setContentType("application/json;charset=utf-8");
            ObjectMapper mapper=new ObjectMapper();
            mapper.writeValue(resp.getWriter(),ok);
        });

        http.formLogin().usernameParameter("user").passwordParameter("pass")
                .loginProcessingUrl("/login")
                .successHandler((req,resp,auth)->{//成功回调
                    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
                    User principal = (User) authentication.getPrincipal();
                    System.err.println(principal);
                    Collection<GrantedAuthority> authorities = principal.getAuthorities();
                    String s = StringUtils.collectionToCommaDelimitedString(authorities);
                    String token = JwtUtils.createToken(principal.getUsername(), s);

                    Result ok = Result.back(token);
                    resp.setContentType("application/json;charset=utf-8");
                    ObjectMapper mapper=new ObjectMapper();
                    mapper.writeValue(resp.getWriter(),ok);
                })
                .failureHandler((req,resp,auth)->{//失败回调
                    Result ok = Result.back(Constant.ERROR.getValue(), "error", "用户名或密码错误!");
                    resp.setContentType("application/json;charset=utf-8");
                    ObjectMapper mapper=new ObjectMapper();
                    mapper.writeValue(resp.getWriter(),ok);
                })
                .permitAll();
        http.authorizeRequests().anyRequest().authenticated().and().cors().and().headers().frameOptions().disable();
    }

    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("*"));
        configuration.setAllowedMethods(Arrays.asList("*"));
        configuration.addAllowedHeader("*");
        configuration.setAllowCredentials(true);
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }
}
